Expand description
Ergonomic paths and files in rust.
This library aims to provide ergonomic path and file operations to rust with reasonable performance.
This includes:
- Improved methods for the
std
path types usingPathInfo
PathMut
andPathOps
- Cleaner absolute paths (which is distinct from canonicalized paths).
- Improved error messages, see the Better Errors section.
- Improved type safety. The types specify that a file/dir once existed and was once a certain type. Obviously a file/dir can be deleted/changed by another process.
- More stringent mutability requirements. See the Differing Method Signatures section.
- Cheap cloning: all path types are
Arc
, which a cheap operation compared to filesystem operations and allows more flexibility and ergonomics in the library for relatively low cost.
§Better Errors
All errors include the path and action which caused the error, as well as the unaltered
std::io::Error
message. Errors are convertable into std::io::Error
, giving almost complete
compatibility with existing code.
§set_len
(i.e. truncate a file):
/* */ std::fs::File::set_len(0)
:Invalid argument (os error 22)
path_abs::FileWrite::set_len(0)
:Invalid argument (os error 22) when setting len for /path/to/example/foo.txt
The above error is actually impossible because
FileWrite
is always writeable, andFileRead
does not implementset_len
. However, it is kept for demonstration.
§open_read
(open file for reading):
/**/ std::fs::File::read(path)
:No such file or directory (os error 2)
path_abs::FileRead::open(path)
:No such file or directory (os error 2) when opening example/foo.txt
And every other method has similarily improved errors. If a method does not have pretty error messages please open a ticket.
§Exported Path Types
These are the exported Path types. All of them are absolute.
PathAbs
: a reference counted absolute (not necessarily canonicalized) path that is not necessarily guaranteed to exist.PathFile
: aPathAbs
that is guaranteed (at instantiation) to exist and be a file, with associated methods.PathDir
: aPathAbs
that is guaranteed (at instantiation) to exist and be a directory, with associated methods.PathType
: an enum containing either a PathFile or a PathDir. Returned byPathDir::list
In addition, all paths are serializable through serde (even on windows!) by using the crate
stfu8
to encode/decode, allowing ill-formed UTF-16. See
that crate for more details on how the resulting encoding can be edited (by hand) even in the
case of what would be ill-formed UTF-16.
§Exported File Types
All File types provide type safe access to their relevant traits. For instance, you can’t
read
with a FileWrite
and you can’t write
with a FileRead
.
FileRead
: a read-only file handle withpath()
attached and improved error messages. Contains only the methods and trait implementations which are allowed by a read-only file.FileWrite
: a write-only file handle withpath()
attached and improved error messages. Contains only the methods and trait implementations which are allowed by a write-only file.FileEdit
: a read/write file handle withpath()
attached and improved error messages. Contains methods and trait implements for both readable and writeable files.
§Differing Method Signatures
The type signatures of the File*
types regarding read
, write
and other methods is
slightly different than std::fs::File
– they all take &mut
instead of &
. This is to
avoid a common possible footgun.
To demonstrate, imagine the following scenario:
- You pass your open
&File
to a method, which puts it in a thread. This thread constantly callsseek(SeekFrom::Start(10))
- You periodically read from a file expecting new data, but are always getting the same data.
Yes, this is actually allowed by the rust compiler since seek
is implemented for
&File
. Technically this is
still memory safe since the operating system will handle any contention, however many would
argue that it isn’t expected that an immutable reference passed to another
function can affect the seek position of a file.
§Examples
Recreating Cargo.init
in example/
use std::path::Path;
use std::collections::HashSet;
use path_abs::{
PathAbs, // absolute path
PathDir, // absolute path to a directory
PathFile, // absolute path to a file
PathType, // enum of Dir or File
PathInfo, // trait for query methods
PathOps, // trait for methods that make new paths
FileRead, // Open read-only file handler
FileWrite, // Open write-only file handler
FileEdit, // Open read/write file handler
};
let example = Path::new("example");
// Create your paths
let project = PathDir::create_all(example)?;
let src = PathDir::create(project.concat("src")?)?;
let lib = PathFile::create(src.concat("lib.rs")?)?;
let cargo = PathFile::create(project.concat("Cargo.toml")?)?;
// Write the templates
lib.write_str(r#"
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}"#)?;
cargo.write_str(r#"
[package]
name = "example"
version = "0.1.0"
authors = ["Garrett Berg <vitiral@gmail.com>"]
[dependencies]
"#)?;
// Put our result into a HashMap so we can assert it
let mut result = HashSet::new();
for p in project.list()? {
result.insert(p?);
}
// Create our expected value
let mut expected = HashSet::new();
expected.insert(PathType::Dir(src));
expected.insert(PathType::File(cargo));
assert_eq!(expected, result);
// ----------------------------------
// Creating types from existing paths
// Creating a generic path
let lib_path = example.join("src").join("lib.rs");
let abs = PathAbs::new(&lib_path)?;
// Or a path with a known type
let file = PathType::new(&lib_path)
?
.unwrap_file();
assert!(abs.is_file());
assert!(file.is_file());
// ----------------------------------
// Opening a File
// open read-only using the PathFile method
let read = file.open_read()?;
// Or use the type directly: open for appending
let write = FileWrite::open_append(&file)?;
// Open for read/write editing.
let edit = file.open_edit()?;
Re-exports§
pub use crate::ser::PathSer;
Modules§
- Open file paths and associated methods.
Structs§
- An error produced by performing an filesystem operation on a
Path
. - A read/write file handle with
path()
attached and improved error messages. Contains methods and trait implements for both readable and writeable files. - A read-only file handle with
path()
attached and improved error messages. Contains only the methods and trait implementations which are allowed by a read-only file. - A write-only file handle with
path()
attached and improved error messages. Contains only the methods and trait implementations which are allowed by a write-only file. - An iterator over
PathType
objects, returned byPathDir::list
. - An absolute (not necessarily canonicalized) path that may or may not exist.
- A
PathAbs
that is guaranteed to be a directory, with associated methods. - a
PathAbs
that was a file at the time of initialization, with associated methods.
Enums§
- An an enum containing either a file or a directory.
Traits§
- Methods that return information about a path.
- Methods that modify a path.
- Methods that return new path-like objects.